package JUC.Lock;

import java.util.concurrent.locks.StampedLock;

/**
 * @author CKC
 * @DateTime 2021/6/13 15:36
 * <p>
 * 注意:
 * *    StampedLock不支持条件变量
 * *    不支持可重入
 * *    使用StampedLock 一定不要调用中断操作     也就是：interrupt()方法
 */
public class StampedLockDemo {
    public static void main(String[] args) throws InterruptedException {
        DataContainerStamped dataContainer = new DataContainerStamped(1);

        new Thread(() -> {
            dataContainer.read(1000);
        }, "t1").start();

        Thread.sleep(500);

        new Thread(() -> {
//            dataContainer.read(0);
            dataContainer.write(1000);
        }, "t2").start();

    }

}

class DataContainerStamped {
    private final StampedLock lock = new StampedLock();
    private int data;

    public DataContainerStamped(int data) {
        this.data = data;
    }

    public int read(int readTime) {
        long stamp = lock.tryOptimisticRead();
        System.out.println(Thread.currentThread().getName() + " Optimistic read locking...." + stamp);
        try {
            Thread.sleep(readTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (lock.validate(stamp)) {//验证有没有被人修改过    true：无人修改   false：被修改过
            System.out.println(Thread.currentThread().getName() + " read finish ..." + stamp);
            return data;
        }

        //锁升级->读锁
        System.out.println(Thread.currentThread().getName() + " updating to read locking..." + stamp);
        try {
            stamp = lock.readLock();
            System.out.println(Thread.currentThread().getName() + "  read lock..." + stamp);
            try {
                Thread.sleep(readTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "  read finish ..." + stamp);
            return data;
        } finally {
            System.out.println(Thread.currentThread().getName() + "  read unlock..." + stamp);
            lock.unlockRead(stamp);
        }
    }

    public void write(int newData) {
        long stamp = lock.writeLock();
        System.out.println(Thread.currentThread().getName() + " write lock..." + stamp);

        try {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.data = newData;
        } finally {
            System.out.println(Thread.currentThread().getName() + " write unlock..." + stamp);
            lock.unlockWrite(stamp);
        }
    }
}
